#include <cmath>
#include <cstring>

#include "Analyst.hpp"

using namespace std;

Token::Token( void )
{
  token_type = INVALID_TYPE;
  value.fvalue = NAN;
}

Token::Token( int _type )
{
  if( _type > -1 && _type < INVALID_TYPE )
    token_type = _type;
}

Analyst::Analyst( void )
{
  static_token[ "point"        ] = Token( PRIMITIVE_POINT );
  static_token[ "line"         ] = Token( PRIMITIVE_LINE );
  static_token[ "pline"        ] = Token( PRIMITIVE_POLYLINE );
  static_token[ "region"       ] = Token( PRIMITIVE_REGION );
  static_token[ "arc"          ] = Token( PRIMITIVE_ARC );
  static_token[ "text"         ] = Token( PRIMITIVE_TEXT );
  static_token[ "roundrect"    ] = Token( PRIMITIVE_ROUNDRECT );
  static_token[ "ellipse"      ] = Token( PRIMITIVE_ELLIPSE );


  static_token[ "symbol"       ] = Token( KEYWORD_SYMBOL );
  static_token[ "pen"          ] = Token( KEYWORD_PEN );
  static_token[ "multiple"     ] = Token( KEYWORD_MULTIPLE );
  static_token[ "smooth"       ] = Token( KEYWORD_SMOOTH );
  static_token[ "brush"        ] = Token( KEYWORD_BRUSH );
  static_token[ "center"       ] = Token( KEYWORD_CENTER );
  static_token[ "font"         ] = Token( KEYWORD_FONT );
  static_token[ "spacing"      ] = Token( KEYWORD_SPACING );
  static_token[ "justify"      ] = Token( KEYWORD_JUSTIFY );
  static_token[ "left"         ] = Token( KEYWORD_LEFT );
  static_token[ "right"        ] = Token( KEYWORD_RIGHT );
  static_token[ "angle"        ] = Token( KEYWORD_ANGLE );
  static_token[ "label"        ] = Token( KEYWORD_LABEL );
  static_token[ "simple"       ] = Token( KEYWORD_SIMPLE );
  static_token[ "arrow"        ] = Token( KEYWORD_ARROW );
}

// 从流里面去掉空格直到第一个字符
void eat_space( ifstream &ifile )
{
  int c;
  do{
    c = ifile.peek();

    if( !isspace( c ) )
      {
	return;
      }
    else
      {
	c = ifile.get( );
      }
  }while( true );
}

Token Analyst::get_token( ifstream& ifile )
{
  Token t;
  if( ifile.eof() )
    {
      return t;
    }
	
  char cur_token_buffer[ TOKEN_STR_MAXLEN ];
  eat_space( ifile );

  char c, *pc = cur_token_buffer;
  for( c = ifile.get(); !isspace(c) && c != '(' && c != EOF; c = ifile.get() )
    {
      *pc++ = tolower( c );
    } // 此时如果遇上TOKEN_STR_MAXLEN过小那就让程序crash吧
  if( c == '(' ){
    ifile.putback( c );
  }
  *pc = '\0';

  // 看看是不是关键字
  std::map<string, Token>::iterator i = static_token.find( cur_token_buffer );
  if( i == static_token.end() )	// 没有，那就只有是两种可能: int|float
    {
      // 通过看有没有小数点判定是不是float
      if( NULL == strchr( cur_token_buffer, '.' ) )
	{
	  if( sscanf( cur_token_buffer, "%d", &t.value.ivalue ) == 0 ){ // 没有成功，是一个异常
	    return t;
	  }else{
	    t.token_type = INTEGER_VALUE;
	    return t;
	  }
	}
      else
	{
	  if( sscanf( cur_token_buffer, "%f", &t.value.fvalue ) == 0 ){ // 没有成功，是一个异常
	    return t;
	  }else{
	    t.token_type = NUMERAL_VALUE;
	    return t;
	  }
	}
    }
  else				// 是关键字
    {
      return i->second;
    }
}
